#ifndef INPUTPARSER_H
#define INPUTPARSER_H
#include<iostream>
using std::cout;using std::endl; using std::string;
#include<vector>
using std::vector;
#include <stack>
using std::stack;
#include<algorithm>
#include<memory>
using std::shared_ptr; using std::make_shared;

class TextQuery;
class Query;
class InputParser{
    public:
        InputParser(TextQuery &t);
        void execQueries(string);
        vector<string> history_;
    private:
        TextQuery& tq_;
        shared_ptr<vector<string>> suffix_;
        shared_ptr<stack<char>> opstack_;
        string inq_;
        shared_ptr<vector<string>> makeSuffix(const string&);   //将中缀表达式的输入转为后缀表达式形式
        Query execSuffix(vector<string>&);  //执行后缀表达式
        bool checkInp(const string&);       //输入验证
        bool chkOp(const char&);            //检查运算符
        bool chkBrk(const string&);         //检查括号匹配
        void processOp(const char&);          //处理后缀表达式生成过程中的运算符
        int cmpOp(const char&,const char&); //比较运算符优先级
        Query cal(const Query&,const string&,const Query&); //对Query根据算符作对应结合运算

        //fun for debug
        void suffixDebug();
        void execDebug();
        void printSuffix();
        void printOpStack();
};

InputParser::InputParser(TextQuery &t)
:tq_(t),suffix_(make_shared<vector<string>>()),opstack_(make_shared<stack<char>>()){}

void InputParser::execQueries(string str){
    if(!inq_.empty())   inq_.clear();
    suffix_.reset();
    suffix_ = make_shared<vector<string>>();
    opstack_.reset();
    opstack_ = make_shared<stack<char>>();

    auto it = std::remove(str.begin(),str.end(),' ');
    str.erase(it,str.end());
    inq_ = str;
    
    if(!checkInp(inq_)){     //输入验证
        cout << "invaild input!";
        return;
    }
    suffix_ = makeSuffix(inq_);
    if(DEBUG) suffixDebug();
    Query q = execSuffix(*suffix_);
    QueryResult qr = q.eval(tq_);
    qr.print();
    history_.push_back(str); //记录结果
}


// 采用逆波兰表示法处理输入
shared_ptr<vector<string>> InputParser::makeSuffix(const string &str){
    auto hd = str.begin(),re = str.begin();
    while(re != str.end()){
        if(isalpha(*re)){
            while(isalpha(*re))
                re++;
            suffix_->push_back(string(hd,re));

            if(!opstack_->empty() && opstack_->top() == '~'){
                suffix_->push_back(string(1,opstack_->top()));
                opstack_->pop();            
            }

            hd = re;
        }
        else{
            processOp(*re);
            hd++; re++;
        }
        // if(DEBUG) suffixDebug();
    }
    while(!opstack_->empty()){
        char &pol = opstack_->top();
        suffix_->push_back(string(1,pol));
        opstack_->pop();
    }

    return suffix_;
}

Query InputParser::execSuffix(vector<string> &suffix){
    stack<Query> calStack;
    for(string str : suffix){
        if(str == "~"){
            Query q = calStack.top(); calStack.pop();
            calStack.push(~q);
        }
        else if(str == "&" || str == "|"){
            Query a = calStack.top(); calStack.pop();
            Query b = calStack.top(); calStack.pop();
            calStack.push(cal(a,str,b));
        }
        else{
            calStack.push(Query(str));
        }
        // if(DEBUG) execDebug();
    }
    return calStack.top();
}

void InputParser::execDebug(){
    cout << "InputParser::execDebug started" << endl;

    cout << "suffix: ";
    for(string &str : *suffix_){
        cout << str << " ";
    }
    cout << endl;
    
    cout << "InputParser::execDebug ends\n\n";
}

Query InputParser::cal(const Query &a,const string &op,const Query &b){  
    if(op == "&")
        return b & a;
    else
        return b | a;
}

bool InputParser::checkInp(const string &str){
    string brkstr;
    for(auto it = str.begin(); it != str.end(); it++){
        if(*it == '(' || *it == ')')
            brkstr.push_back(*it);
        else if(*it == '~'){
            continue;
        }
        else if(*it  == '&' || *it  == '|'){
            continue;
        }
        else if(!isalpha(*it))
            return false;        
    }
    return chkBrk(brkstr);
}


bool InputParser::chkBrk(const string &str){
    stack<char> brksta;
    for(char ch : str){
        if(ch == '(')  brksta.push(')');
        else if(brksta.empty() || brksta.top() != ch)   return false;
        else brksta.pop();        
    }
    return brksta.empty();
}

void InputParser::processOp(const char &ch){
    if(opstack_->empty()){
        opstack_->push(ch);
        return;
    }

    if(ch == '(' || ch == '~'){
        opstack_->push(ch);
    }
    else if(ch == ')'){  
        char &pol = opstack_->top();
        while(pol != '('){  //若遇到则右括号，不断出栈至弹出左括号
            suffix_->push_back(string(1,pol));
            opstack_->pop();
            pol = opstack_->top();
        }
        opstack_->pop();
    }
    else if( cmpOp(ch,opstack_->top()) == 1) {    
        opstack_->push(ch);           
    }
    else{
        char &pol = opstack_->top();
        while(!opstack_->empty() && cmpOp(ch,pol) == -1){
            pol = opstack_->top();
            suffix_->push_back(string(1,pol));
            opstack_->pop();
        }
        opstack_->push(ch); 
    }
} 

int InputParser::cmpOp(const char &op1,const char &op2){
    if(op1 == '|' && op2 == '&')
        return -1;
    else 
        return 1;
    
}

void InputParser::suffixDebug(){
    cout << "suffix: ";
    printSuffix();
    cout << "opstack: ";
    printOpStack();
    cout << "\n\n";
}

void InputParser::printSuffix(){
    for(string &ch : *suffix_){
        cout << ch << " ";
    }
    cout << endl;
}

void InputParser::printOpStack(){
    if(opstack_->empty())
        return;
    char x = opstack_->top();
    opstack_->pop();
    printOpStack();
    cout << x << " ";
    opstack_->push(x);
}

#endif  //InputParser_H
